﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;

namespace TechnicalAnalysisEngine.Tests
{
    [TestClass]
    public class TestWilliamsR
    {
        List<double> highs;
        List<double> lows;
        List<double> closes;
        List<double> expectedValues;

        int periods;
        int expectedOffset;

        [TestInitialize]
        public void Initialize()
        {
            highs = new List<double>()
            {
                127.01,127.62,126.59,127.35,128.17,128.43,127.37,126.42,126.90,126.85,125.65,125.72,
                127.16,127.72,127.69,128.22,128.27,128.09,128.27,127.74,128.77,129.29,130.06,129.12,
                129.29,128.47,128.09,128.65,129.14,128.64
            };

            lows = new List<double>()
            {
                125.36,126.16,124.93,126.09,126.82,126.48,126.03,124.83,126.39,125.72,124.56,124.57,
                125.07,126.86,126.63,126.80,126.71,126.80,126.13,125.92,126.99,127.81,128.47,128.06,
                127.61,127.60,127.00,126.90,127.49,127.40
            };

            closes = new List<double>()
            {
                1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,127.29,127.18,128.01,
                127.11,127.73,127.06,127.33,128.71,127.87,128.58,128.60,127.93,128.11,127.60,127.60,128.69,128.27
            };

            expectedValues = new List<double>()
            {
                -29.56,-32.39,-10.80,-34.19,-18.25,-35.48,-25.47,-1.42,-29.90,-26.94,-26.58,-38.77,-39.04,-59.61,-59.61,-33.17,-43.27
            };

            periods = 14;
            expectedOffset = 13;
        }

        [TestMethod]
        public void TestWilliamsRValues()
        {
            var result = AnalysisEngine.WilliamsR(highs, lows, closes, periods);

            Assert.AreEqual(expectedOffset, result.StartIndexOffset);
            Assert.AreEqual(expectedValues.Count, result.Values.Count);

            string message = null;
            bool testResult = true;

            for (int i = 0; i < result.Values.Count; i++)
            {
                if (!TestHelpers.EqualsWithTolerance(result.Values[i], expectedValues[i], 1)) // 1% tolerance from expected results
                {
                    message = string.Format("Values do not match at position {0}, expected: {1}, actual: {2} ",
                        i, expectedValues[i], result.Values[i]);

                    testResult = false;
                    break;
                }
            }

            Assert.IsTrue(testResult, message);
        }

        [TestMethod]
        public void TestWilliamsRPerformance()
        {
            Random random = new Random();
            var randomlyGeneratedHighs = new List<double>();
            var randomlyGeneratedLows = new List<double>();
            var randomlyGeneratedCloses = new List<double>();

            for (int i = 0; i < 10000; i++)
            {
                randomlyGeneratedHighs.Add(random.Next(85, 90));
                randomlyGeneratedLows.Add(random.Next(80, 85));
                randomlyGeneratedCloses.Add(random.Next(83, 87));
            }

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            AnalysisEngine.WilliamsR(randomlyGeneratedHighs, randomlyGeneratedLows, randomlyGeneratedCloses, periods);

            stopWatch.Stop();
            Console.WriteLine(string.Format("ATR, {0} values, {1} μs", randomlyGeneratedHighs.Count, stopWatch.ElapsedTicks / 10));
        }
    }
}
